#include "session.h"

net_tcp::session::session(asio::io_service& iosev) :m_iosev(iosev),m_socket(iosev),enable_shared_from_this(*this),
	m_recv_buffer(BUFF_SIZE),
	m_send_buffer(BUFF_SIZE)
{
	m_id = (int)this;
}

net_tcp::session::~session()
{
}

bool net_tcp::session::send(std::string data)
{
	return send(data.c_str(),data.length());
}

bool net_tcp::session::send(const char* data, int len)
{
	if (m_socket.is_open())
	{
		std::string copydata = std::string(data, len);
		m_iosev.post([this, copydata]()->void {
			m_send_buffer.write(copydata.c_str(),copydata.length());
			this->do_async_send();
		});
		return true;
	}
	return false;
}

void net_tcp::session::read_loop()
{
	do_async_read();
}

void net_tcp::session::do_async_read()
{
	if (m_socket.is_open() && !m_async_reading) {
		m_async_reading = true;
		m_recv_buffer.prepare_write(DATA_SIZE);
		m_socket.async_read_some(asio::buffer(m_recv_buffer.write_pointer(), DATA_SIZE),
			[this](asio::error_code error, std::size_t length) -> void
			{
				m_async_reading = false;
				if (error) {
					this->on_error(error);
					this->close();
				}
				else {
					m_recv_buffer.increase_write(length);
					this->on_recv();
					this->do_async_read();
				}
			}
		);
	}
}

void net_tcp::session::do_async_send()
{
	if (m_socket.is_open() && !m_async_sending) {

		int peekSize = m_send_buffer.readable_size();
		if (peekSize <= 0)
			return;

		if (peekSize > DATA_SIZE) {
			peekSize = DATA_SIZE;
		}

		m_async_sending = true;
		m_socket.async_write_some(asio::buffer(m_send_buffer.read_pointer(), peekSize),
			[this](asio::error_code error, std::size_t writeLen)->void
			{
				m_async_sending = false;

				if (error)
				{
					m_last_err = error;
					this->close();
				}
				else {
					m_send_buffer.increase_read(writeLen);
					this->do_async_send();
				}
			}
		);
	}
}

void net_tcp::session::close()
{
	if (m_socket.is_open())
	{
		m_socket.shutdown(asio::ip::tcp::socket::shutdown_both, m_last_err);
		m_socket.close();
	}

	if (m_on_close)
	{
		m_on_close(shared_from_this());
	}
}

void net_tcp::session::on_error(asio::error_code error)
{
	if (m_on_error)
	{
		m_on_error(shared_from_this());
	}
}

void net_tcp::session::on_recv()
{
	if (m_on_recv)
	{
		m_on_recv(shared_from_this());
	}
}
